/*
 * Copyright 2023-2024, Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * LoongArch64架构浮点运算支持
 */

#ifndef _LOONGARCH64_FP_ARCH_H
#define _LOONGARCH64_FP_ARCH_H

#include <stdint.h>

/* LoongArch64架构浮点运算优化 */

/* fp_barrier确保编译器不会优化掉浮点操作 */
static inline float fp_barrierf(float x)
{
	volatile float y = x;
	return y;
}

static inline double fp_barrier(double x)
{
	volatile double y = x;
	return y;
}

static inline long double fp_barrierl(long double x)
{
	volatile long double y = x;
	return y;
}

/* fp_force_eval确保浮点计算被执行，即使结果未被使用 */
#define fp_force_evalf fp_force_evalf
static inline void fp_force_evalf(float x)
{
	volatile float y;
	y = x;
}

#define fp_force_eval fp_force_eval
static inline void fp_force_eval(double x)
{
	volatile double y;
	y = x;
}

#define fp_force_evall fp_force_evall
static inline void fp_force_evall(long double x)
{
	volatile long double y;
	y = x;
}

/* LoongArch64特定的浮点操作优化 */

/* 检查CPU特性的辅助函数 */
static inline uint32_t read_cpucfg(uint32_t reg)
{
	uint32_t result;
	__asm__ __volatile__(
		"cpucfg %0, %1\n\t"
		: "=r"(result)
		: "r"(reg)
	);
	return result;
}

/* 读取CSR寄存器的辅助函数 */
static inline uint64_t read_csr(uint32_t reg)
{
	uint64_t result;
	__asm__ __volatile__(
		"csrrd %0, %1\n\t"
		: "=r"(result)
		: "i"(reg)
	);
	return result;
}

/* 写入CSR寄存器的辅助函数 */
static inline void write_csr(uint32_t reg, uint64_t val)
{
	__asm__ __volatile__(
		"csrwr %0, %1\n\t"
		:
		: "r"(val), "i"(reg)
		: "memory"
	);
}

/* 获取FCSR寄存器值 */
static inline uint32_t get_fcsr(void)
{
	uint32_t fcsr;
	__asm__ __volatile__(
		"movfcsr2gr %0, $fcsr0\n\t"
		: "=r"(fcsr)
	);
	return fcsr;
}

/* 设置FCSR寄存器值 */
static inline void set_fcsr(uint32_t fcsr)
{
	__asm__ __volatile__(
		"movgr2fcsr $fcsr0, %0\n\t"
		:
		: "r"(fcsr)
	);
}

/* 检查是否支持LSX/LASX向量扩展 */
static inline int has_lsx_support(void)
{
	/* 检查CPUCFG寄存器中的LSX支持位 */
	uint32_t cpucfg2 = read_cpucfg(2);
	return (cpucfg2 >> 6) & 1; /* LSX支持位在CPUCFG2的第6位 */
}

static inline int has_lasx_support(void)
{
	/* 检查CPUCFG寄存器中的LASX支持位 */
	uint32_t cpucfg2 = read_cpucfg(2);
	return (cpucfg2 >> 7) & 1; /* LASX支持位在CPUCFG2的第7位 */
}

/* LoongArch64融合乘加操作 (Fused Multiply-Add) */
static inline float fmaf_loongarch(float x, float y, float z)
{
	float result;
	if (has_lsx_support()) {
		__asm__ __volatile__(
			"fmadd.s %0, %1, %2, %3\n\t"
			: "=f"(result)
			: "f"(x), "f"(y), "f"(z)
		);
		return result;
	} else {
		/* 软件实现，当硬件不支持时使用 */
		return x * y + z;
	}
}

static inline double fma_loongarch(double x, double y, double z)
{
	double result;
	if (has_lsx_support()) {
		__asm__ __volatile__(
			"fmadd.d %0, %1, %2, %3\n\t"
			: "=f"(result)
			: "f"(x), "f"(y), "f"(z)
		);
		return result;
	} else {
		/* 软件实现，当硬件不支持时使用 */
		return x * y + z;
	}
}

/* LoongArch64融合乘减操作 (Fused Multiply-Subtract) */
static inline float fmsf_loongarch(float x, float y, float z)
{
	float result;
	__asm__ __volatile__(
		"fmsub.s %0, %1, %2, %3\n\t"
		: "=f"(result)
		: "f"(x), "f"(y), "f"(z)
	);
	return result;
}

static inline double fms_loongarch(double x, double y, double z)
{
	double result;
	__asm__ __volatile__(
		"fmsub.d %0, %1, %2, %3\n\t"
		: "=f"(result)
		: "f"(x), "f"(y), "f"(z)
	);
	return result;
}

/* LoongArch64反向融合乘加操作 (Negative Fused Multiply-Add) */
static inline float fnmaf_loongarch(float x, float y, float z)
{
	float result;
	__asm__ __volatile__(
		"fnmadd.s %0, %1, %2, %3\n\t"
		: "=f"(result)
		: "f"(x), "f"(y), "f"(z)
	);
	return result;
}

static inline double fnma_loongarch(double x, double y, double z)
{
	double result;
	__asm__ __volatile__(
		"fnmadd.d %0, %1, %2, %3\n\t"
		: "=f"(result)
		: "f"(x), "f"(y), "f"(z)
	);
	return result;
}

/* LoongArch64反向融合乘减操作 (Negative Fused Multiply-Subtract) */
static inline float fnmsf_loongarch(float x, float y, float z)
{
	float result;
	__asm__ __volatile__(
		"fnmsub.s %0, %1, %2, %3\n\t"
		: "=f"(result)
		: "f"(x), "f"(y), "f"(z)
	);
	return result;
}

static inline double fnms_loongarch(double x, double y, double z)
{
	double result;
	__asm__ __volatile__(
		"fnmsub.d %0, %1, %2, %3\n\t"
		: "=f"(result)
		: "f"(x), "f"(y), "f"(z)
	);
	return result;
}

/* LSX向量扩展浮点运算支持 */
#ifdef __loongarch_sx

/* LSX向量类型定义 */
typedef float __v4sf __attribute__ ((vector_size (16)));
typedef double __v2df __attribute__ ((vector_size (16)));

/* LSX向量加载和存储操作 */
static inline __v4sf lsx_vld_float(const float *addr)
{
	__v4sf result;
	__asm__ __volatile__(
		"vld $vr0, %1\n\t"
		"vmov.v %0, $vr0\n\t"
		: "=f"(result)
		: "m"(*addr)
		: "$vr0"
	);
	return result;
}

static inline __v2df lsx_vld_double(const double *addr)
{
	__v2df result;
	__asm__ __volatile__(
		"vld $vr0, %1\n\t"
		"vmov.v %0, $vr0\n\t"
		: "=f"(result)
		: "m"(*addr)
		: "$vr0"
	);
	return result;
}

static inline void lsx_vst_float(__v4sf data, float *addr)
{
	__asm__ __volatile__(
		"vmov.v $vr0, %1\n\t"
		"vst $vr0, %0\n\t"
		: "=m"(*addr)
		: "f"(data)
		: "$vr0"
	);
}

static inline void lsx_vst_double(__v2df data, double *addr)
{
	__asm__ __volatile__(
		"vmov.v $vr0, %1\n\t"
		"vst $vr0, %0\n\t"
		: "=m"(*addr)
		: "f"(data)
		: "$vr0"
	);
}

/* LSX向量浮点运算操作 */
static inline __v4sf lsx_vfadd_s(__v4sf a, __v4sf b)
{
	__v4sf result;
	__asm__ __volatile__(
		"vfadd.s %0, %1, %2\n\t"
		: "=f"(result)
		: "f"(a), "f"(b)
	);
	return result;
}

static inline __v2df lsx_vfadd_d(__v2df a, __v2df b)
{
	__v2df result;
	__asm__ __volatile__(
		"vfadd.d %0, %1, %2\n\t"
		: "=f"(result)
		: "f"(a), "f"(b)
	);
	return result;
}

static inline __v4sf lsx_vfsub_s(__v4sf a, __v4sf b)
{
	__v4sf result;
	__asm__ __volatile__(
		"vfsub.s %0, %1, %2\n\t"
		: "=f"(result)
		: "f"(a), "f"(b)
	);
	return result;
}

static inline __v2df lsx_vfsub_d(__v2df a, __v2df b)
{
	__v2df result;
	__asm__ __volatile__(
		"vfsub.d %0, %1, %2\n\t"
		: "=f"(result)
		: "f"(a), "f"(b)
	);
	return result;
}

static inline __v4sf lsx_vfmul_s(__v4sf a, __v4sf b)
{
	__v4sf result;
	__asm__ __volatile__(
		"vfmul.s %0, %1, %2\n\t"
		: "=f"(result)
		: "f"(a), "f"(b)
	);
	return result;
}

static inline __v2df lsx_vfmul_d(__v2df a, __v2df b)
{
	__v2df result;
	__asm__ __volatile__(
		"vfmul.d %0, %1, %2\n\t"
		: "=f"(result)
		: "f"(a), "f"(b)
	);
	return result;
}

static inline __v4sf lsx_vfdiv_s(__v4sf a, __v4sf b)
{
	__v4sf result;
	__asm__ __volatile__(
		"vfdiv.s %0, %1, %2\n\t"
		: "=f"(result)
		: "f"(a), "f"(b)
	);
	return result;
}

static inline __v2df lsx_vfdiv_d(__v2df a, __v2df b)
{
	__v2df result;
	__asm__ __volatile__(
		"vfdiv.d %0, %1, %2\n\t"
		: "=f"(result)
		: "f"(a), "f"(b)
	);
	return result;
}

/* LSX向量融合乘加操作 */
static inline __v4sf lsx_vfmadd_s(__v4sf a, __v4sf b, __v4sf c)
{
	__v4sf result;
	__asm__ __volatile__(
		"vfmadd.s %0, %1, %2, %3\n\t"
		: "=f"(result)
		: "f"(a), "f"(b), "f"(c)
	);
	return result;
}

static inline __v2df lsx_vfmadd_d(__v2df a, __v2df b, __v2df c)
{
	__v2df result;
	__asm__ __volatile__(
		"vfmadd.d %0, %1, %2, %3\n\t"
		: "=f"(result)
		: "f"(a), "f"(b), "f"(c)
	);
	return result;
}

/* LSX向量融合乘减操作 */
static inline __v4sf lsx_vfmsub_s(__v4sf a, __v4sf b, __v4sf c)
{
	__v4sf result;
	__asm__ __volatile__(
		"vfmsub.s %0, %1, %2, %3\n\t"
		: "=f"(result)
		: "f"(a), "f"(b), "f"(c)
	);
	return result;
}

static inline __v2df lsx_vfmsub_d(__v2df a, __v2df b, __v2df c)
{
	__v2df result;
	__asm__ __volatile__(
		"vfmsub.d %0, %1, %2, %3\n\t"
		: "=f"(result)
		: "f"(a), "f"(b), "f"(c)
	);
	return result;
}

/* LSX向量反向融合乘加操作 */
static inline __v4sf lsx_vfnmadd_s(__v4sf a, __v4sf b, __v4sf c)
{
	__v4sf result;
	__asm__ __volatile__(
		"vfnmadd.s %0, %1, %2, %3\n\t"
		: "=f"(result)
		: "f"(a), "f"(b), "f"(c)
	);
	return result;
}

static inline __v2df lsx_vfnmadd_d(__v2df a, __v2df b, __v2df c)
{
	__v2df result;
	__asm__ __volatile__(
		"vfnmadd.d %0, %1, %2, %3\n\t"
		: "=f"(result)
		: "f"(a), "f"(b), "f"(c)
	);
	return result;
}

/* LSX向量反向融合乘减操作 */
static inline __v4sf lsx_vfnmsub_s(__v4sf a, __v4sf b, __v4sf c)
{
	__v4sf result;
	__asm__ __volatile__(
		"vfnmsub.s %0, %1, %2, %3\n\t"
		: "=f"(result)
		: "f"(a), "f"(b), "f"(c)
	);
	return result;
}

static inline __v2df lsx_vfnmsub_d(__v2df a, __v2df b, __v2df c)
{
	__v2df result;
	__asm__ __volatile__(
		"vfnmsub.d %0, %1, %2, %3\n\t"
		: "=f"(result)
		: "f"(a), "f"(b), "f"(c)
	);
	return result;
}

/* LSX向量平方根操作 */
static inline __v4sf lsx_vfsqrt_s(__v4sf a)
{
	__v4sf result;
	__asm__ __volatile__(
		"vfsqrt.s %0, %1\n\t"
		: "=f"(result)
		: "f"(a)
	);
	return result;
}

static inline __v2df lsx_vfsqrt_d(__v2df a)
{
	__v2df result;
	__asm__ __volatile__(
		"vfsqrt.d %0, %1\n\t"
		: "=f"(result)
		: "f"(a)
	);
	return result;
}

/* LSX向量倒数平方根操作 */
static inline __v4sf lsx_vfrsqrt_s(__v4sf a)
{
	__v4sf result;
	__asm__ __volatile__(
		"vfrsqrt.s %0, %1\n\t"
		: "=f"(result)
		: "f"(a)
	);
	return result;
}

static inline __v2df lsx_vfrsqrt_d(__v2df a)
{
	__v2df result;
	__asm__ __volatile__(
		"vfrsqrt.d %0, %1\n\t"
		: "=f"(result)
		: "f"(a)
	);
	return result;
}

/* LSX向量倒数操作 */
static inline __v4sf lsx_vfrec_s(__v4sf a)
{
	__v4sf result;
	__asm__ __volatile__(
		"vfrec.s %0, %1\n\t"
		: "=f"(result)
		: "f"(a)
	);
	return result;
}

static inline __v2df lsx_vfrec_d(__v2df a)
{
	__v2df result;
	__asm__ __volatile__(
		"vfrec.d %0, %1\n\t"
		: "=f"(result)
		: "f"(a)
	);
	return result;
}

#endif /* __loongarch_sx */

/* LASX高级向量扩展浮点运算支持 */
#ifdef __loongarch_asx

/* LASX向量类型定义 */
typedef float __v8sf __attribute__ ((vector_size (32)));
typedef double __v4df __attribute__ ((vector_size (32)));

/* LASX向量加载和存储操作 */
static inline __v8sf lasx_xvld_float(const float *addr)
{
	__v8sf result;
	__asm__ __volatile__(
		"xvld $xr0, %1\n\t"
		"xvmov.v %0, $xr0\n\t"
		: "=f"(result)
		: "m"(*addr)
		: "$xr0"
	);
	return result;
}

static inline __v4df lasx_xvld_double(const double *addr)
{
	__v4df result;
	__asm__ __volatile__(
		"xvld $xr0, %1\n\t"
		"xvmov.v %0, $xr0\n\t"
		: "=f"(result)
		: "m"(*addr)
		: "$xr0"
	);
	return result;
}

static inline void lasx_xvst_float(__v8sf data, float *addr)
{
	__asm__ __volatile__(
		"xvmov.v $xr0, %1\n\t"
		"xvst $xr0, %0\n\t"
		: "=m"(*addr)
		: "f"(data)
		: "$xr0"
	);
}

static inline void lasx_xvst_double(__v4df data, double *addr)
{
	__asm__ __volatile__(
		"xvmov.v $xr0, %1\n\t"
		"xvst $xr0, %0\n\t"
		: "=m"(*addr)
		: "f"(data)
		: "$xr0"
	);
}

/* LASX向量浮点运算操作 */
static inline __v8sf lasx_xvfadd_s(__v8sf a, __v8sf b)
{
	__v8sf result;
	__asm__ __volatile__(
		"xvfadd.s %0, %1, %2\n\t"
		: "=f"(result)
		: "f"(a), "f"(b)
	);
	return result;
}

static inline __v4df lasx_xvfadd_d(__v4df a, __v4df b)
{
	__v4df result;
	__asm__ __volatile__(
		"xvfadd.d %0, %1, %2\n\t"
		: "=f"(result)
		: "f"(a), "f"(b)
	);
	return result;
}

static inline __v8sf lasx_xvfsub_s(__v8sf a, __v8sf b)
{
	__v8sf result;
	__asm__ __volatile__(
		"xvfsub.s %0, %1, %2\n\t"
		: "=f"(result)
		: "f"(a), "f"(b)
	);
	return result;
}

static inline __v4df lasx_xvfsub_d(__v4df a, __v4df b)
{
	__v4df result;
	__asm__ __volatile__(
		"xvfsub.d %0, %1, %2\n\t"
		: "=f"(result)
		: "f"(a), "f"(b)
	);
	return result;
}

static inline __v8sf lasx_xvfmul_s(__v8sf a, __v8sf b)
{
	__v8sf result;
	__asm__ __volatile__(
		"xvfmul.s %0, %1, %2\n\t"
		: "=f"(result)
		: "f"(a), "f"(b)
	);
	return result;
}

static inline __v4df lasx_xvfmul_d(__v4df a, __v4df b)
{
	__v4df result;
	__asm__ __volatile__(
		"xvfmul.d %0, %1, %2\n\t"
		: "=f"(result)
		: "f"(a), "f"(b)
	);
	return result;
}

static inline __v8sf lasx_xvfdiv_s(__v8sf a, __v8sf b)
{
	__v8sf result;
	__asm__ __volatile__(
		"xvfdiv.s %0, %1, %2\n\t"
		: "=f"(result)
		: "f"(a), "f"(b)
	);
	return result;
}

static inline __v4df lasx_xvfdiv_d(__v4df a, __v4df b)
{
	__v4df result;
	__asm__ __volatile__(
		"xvfdiv.d %0, %1, %2\n\t"
		: "=f"(result)
		: "f"(a), "f"(b)
	);
	return result;
}

/* LASX向量融合乘加操作 */
static inline __v8sf lasx_xvfmadd_s(__v8sf a, __v8sf b, __v8sf c)
{
	__v8sf result;
	__asm__ __volatile__(
		"xvfmadd.s %0, %1, %2, %3\n\t"
		: "=f"(result)
		: "f"(a), "f"(b), "f"(c)
	);
	return result;
}

static inline __v4df lasx_xvfmadd_d(__v4df a, __v4df b, __v4df c)
{
	__v4df result;
	__asm__ __volatile__(
		"xvfmadd.d %0, %1, %2, %3\n\t"
		: "=f"(result)
		: "f"(a), "f"(b), "f"(c)
	);
	return result;
}

/* LASX向量融合乘减操作 */
static inline __v8sf lasx_xvfmsub_s(__v8sf a, __v8sf b, __v8sf c)
{
	__v8sf result;
	__asm__ __volatile__(
		"xvfmsub.s %0, %1, %2, %3\n\t"
		: "=f"(result)
		: "f"(a), "f"(b), "f"(c)
	);
	return result;
}

static inline __v4df lasx_xvfmsub_d(__v4df a, __v4df b, __v4df c)
{
	__v4df result;
	__asm__ __volatile__(
		"xvfmsub.d %0, %1, %2, %3\n\t"
		: "=f"(result)
		: "f"(a), "f"(b), "f"(c)
	);
	return result;
}

/* LASX向量反向融合乘加操作 */
static inline __v8sf lasx_xvfnmadd_s(__v8sf a, __v8sf b, __v8sf c)
{
	__v8sf result;
	__asm__ __volatile__(
		"xvfnmadd.s %0, %1, %2, %3\n\t"
		: "=f"(result)
		: "f"(a), "f"(b), "f"(c)
	);
	return result;
}

static inline __v4df lasx_xvfnmadd_d(__v4df a, __v4df b, __v4df c)
{
	__v4df result;
	__asm__ __volatile__(
		"xvfnmadd.d %0, %1, %2, %3\n\t"
		: "=f"(result)
		: "f"(a), "f"(b), "f"(c)
	);
	return result;
}

/* LASX向量反向融合乘减操作 */
static inline __v8sf lasx_xvfnmsub_s(__v8sf a, __v8sf b, __v8sf c)
{
	__v8sf result;
	__asm__ __volatile__(
		"xvfnmsub.s %0, %1, %2, %3\n\t"
		: "=f"(result)
		: "f"(a), "f"(b), "f"(c)
	);
	return result;
}

static inline __v4df lasx_xvfnmsub_d(__v4df a, __v4df b, __v4df c)
{
	__v4df result;
	__asm__ __volatile__(
		"xvfnmsub.d %0, %1, %2, %3\n\t"
		: "=f"(result)
		: "f"(a), "f"(b), "f"(c)
	);
	return result;
}

/* LASX向量平方根操作 */
static inline __v8sf lasx_xvfsqrt_s(__v8sf a)
{
	__v8sf result;
	__asm__ __volatile__(
		"xvfsqrt.s %0, %1\n\t"
		: "=f"(result)
		: "f"(a)
	);
	return result;
}

static inline __v4df lasx_xvfsqrt_d(__v4df a)
{
	__v4df result;
	__asm__ __volatile__(
		"xvfsqrt.d %0, %1\n\t"
		: "=f"(result)
		: "f"(a)
	);
	return result;
}

/* LASX向量倒数平方根操作 */
static inline __v8sf lasx_xvfrsqrt_s(__v8sf a)
{
	__v8sf result;
	__asm__ __volatile__(
		"xvfrsqrt.s %0, %1\n\t"
		: "=f"(result)
		: "f"(a)
	);
	return result;
}

static inline __v4df lasx_xvfrsqrt_d(__v4df a)
{
	__v4df result;
	__asm__ __volatile__(
		"xvfrsqrt.d %0, %1\n\t"
		: "=f"(result)
		: "f"(a)
	);
	return result;
}

/* LASX向量倒数操作 */
static inline __v8sf lasx_xvfrec_s(__v8sf a)
{
	__v8sf result;
	__asm__ __volatile__(
		"xvfrec.s %0, %1\n\t"
		: "=f"(result)
		: "f"(a)
	);
	return result;
}

static inline __v4df lasx_xvfrec_d(__v4df a)
{
	__v4df result;
	__asm__ __volatile__(
		"xvfrec.d %0, %1\n\t"
		: "=f"(result)
		: "f"(a)
	);
	return result;
}
#endif /* __loongarch_asx */

/* LoongArch64单精度浮点运算优化 */
static inline float sqrtf_loongarch(float x)
{
	float result;
	__asm__ __volatile__(
		"fsqrt.s %0, %1\n\t"
		: "=f"(result)
		: "f"(x)
	);
	return result;
}

static inline double sqrt_loongarch(double x)
{
	double result;
	__asm__ __volatile__(
		"fsqrt.d %0, %1\n\t"
		: "=f"(result)
		: "f"(x)
	);
	return result;
}

/* LoongArch64浮点倒数近似值 */
static inline float frecipf_loongarch(float x)
{
	float result;
	__asm__ __volatile__(
		"frecip.s %0, %1\n\t"
		: "=f"(result)
		: "f"(x)
	);
	return result;
}

static inline double frecip_loongarch(double x)
{
	double result;
	__asm__ __volatile__(
		"frecip.d %0, %1\n\t"
		: "=f"(result)
		: "f"(x)
	);
	return result;
}

/* LoongArch64浮点倒数平方根近似值 */
static inline float frsqrtf_loongarch(float x)
{
	float result;
	__asm__ __volatile__(
		"frsqrt.s %0, %1\n\t"
		: "=f"(result)
		: "f"(x)
	);
	return result;
}

static inline double frsqrt_loongarch(double x)
{
	double result;
	__asm__ __volatile__(
		"frsqrt.d %0, %1\n\t"
		: "=f"(result)
		: "f"(x)
	);
	return result;
}

/* LoongArch64浮点比较操作 */
static inline int fcmp_eq_s(float x, float y)
{
	int result;
	__asm__ __volatile__(
		"fcmp.seq.s $fcc0, %1, %2\n\t"
		"movcf2gr %0, $fcc0\n\t"
		: "=r"(result)
		: "f"(x), "f"(y)
	);
	return result;
}

static inline int fcmp_eq_d(double x, double y)
{
	int result;
	__asm__ __volatile__(
		"fcmp.seq.d $fcc0, %1, %2\n\t"
		"movcf2gr %0, $fcc0\n\t"
		: "=r"(result)
		: "f"(x), "f"(y)
	);
	return result;
}

static inline int fcmp_lt_s(float x, float y)
{
	int result;
	__asm__ __volatile__(
		"fcmp.slt.s $fcc0, %1, %2\n\t"
		"movcf2gr %0, $fcc0\n\t"
		: "=r"(result)
		: "f"(x), "f"(y)
	);
	return result;
}

static inline int fcmp_lt_d(double x, double y)
{
	int result;
	__asm__ __volatile__(
		"fcmp.slt.d $fcc0, %1, %2\n\t"
		"movcf2gr %0, $fcc0\n\t"
		: "=r"(result)
		: "f"(x), "f"(y)
	);
	return result;
}

/* LoongArch64浮点舍入模式控制 */
#define FCSR_RM_MASK 0x300
#define FCSR_RM_RNE  0x000  /* 舍入到最接近的偶数 */
#define FCSR_RM_RTZ  0x100  /* 舍入到零 */
#define FCSR_RM_RDN  0x200  /* 舍入到负无穷 */
#define FCSR_RM_RUP  0x300  /* 舍入到正无穷 */

/* 设置浮点舍入模式 */
static inline uint32_t set_float_rounding_mode(uint32_t mode)
{
	uint32_t old_fcsr = get_fcsr();
	uint32_t new_fcsr = (old_fcsr & ~FCSR_RM_MASK) | (mode & FCSR_RM_MASK);
	set_fcsr(new_fcsr);
	return old_fcsr & FCSR_RM_MASK;
}

/* 获取当前浮点舍入模式 */
static inline uint32_t get_float_rounding_mode(void)
{
	return get_fcsr() & FCSR_RM_MASK;
}

#endif /* _LOONGARCH64_FP_ARCH_H */